package com.paziy.jan.fraction;

/**
 * Created with IntelliJ IDEA.
 * User: paziy
 * Date: 30.10.12
 * Time: 19:48
 * To change this template use File | Settings | File Templates.
 */
public class FMath {

    /**
     * Find GCD of a and b
     *
     * @param a int value
     * @param b int value
     * @return int value
     */
    public static final int gcd(int a, int b) {
        if (a == 0 || b == 0 || a == 1 || b == 1) {
            return 1;
        }

        a = java.lang.Math.abs(a);
        b = java.lang.Math.abs(b);

        if (b > a) {
            int tmp;
            tmp = b;
            b = a;
            a = tmp;
        }

        if (a % b == 0) {
            return b;
        } else {
            return gcd(b, a % b);
        }
    }

    /**
     * Find LCM of a and b
     *
     * @param a int value
     * @param b int value
     * @return int value
     */
    public static final int lcm(int a, int b) {
        return a * b / gcd(a, b);
    }


    /**
     * Sum of fraction with fraction or double values
     *
     * @param a
     * @param b
     * @return
     */
    public static final Fraction sum(Fraction a, Fraction b) {
        int lcmAB = lcm(a.getDenominator(), b.getDenominator());
        return new Fraction(lcmAB / a.getDenominator() * a.getNumerator() + lcmAB / b.getDenominator() * b.getNumerator(), lcmAB);
    }

    public static final Fraction sum(Fraction... fractions) {
        Fraction result = new Fraction(0);

        for (Fraction fr : fractions) {
            result = sum(result, fr);
        }

        return result;
    }

    public static final Fraction sum(Fraction a, int b) {
        return sum(a, new Fraction(b));
    }

    public static final Fraction sum(int a, Fraction b) {
        return sum(new Fraction(a), b);
    }

    public static final Fraction sum(Fraction a, double b) {
        return sum(a, new Fraction(b));
    }

    public static final Fraction sum(double a, Fraction b) {
        return sum(new Fraction(a), b);
    }

    public static final Fraction sum(double a, double b) {
        return new Fraction(a + b);
    }

    /**
     * Subtraction of fraction with fraction or integer or double values
     *
     * @param subtractor
     * @param subtrahend
     * @return
     */
    public static final Fraction subtraction(Fraction subtractor, Fraction subtrahend) {
        int lcmAB = lcm(subtractor.getDenominator(), subtrahend.getDenominator());
        return new Fraction(lcmAB / subtractor.getDenominator() * subtractor.getNumerator() -
                lcmAB / subtrahend.getDenominator() * subtrahend.getNumerator(), lcmAB);
    }

    public static final Fraction subtraction(Fraction... fractions) {
        Fraction result = fractions[0];

        for (int i = 1; i < fractions.length; i++) {
            result = subtraction(result, fractions[i]);
        }

        return result;
    }

    public static final Fraction subtraction(Fraction subtractor, int subtrahend) {
        return subtraction(subtractor, new Fraction(subtrahend));
    }

    public static final Fraction subtraction(int subtractor, Fraction subtrahend) {
        return subtraction(new Fraction(subtractor), subtrahend);
    }

    public static final Fraction subtraction(Fraction subtractor, double subtrahend) {
        return subtraction(subtractor, new Fraction(subtrahend));
    }

    public static final Fraction subtraction(double subtractor, Fraction subtrahend) {
        return subtraction(new Fraction(subtractor), subtrahend);
    }

    public static final Fraction subtraction(double subtractor, double subtrahend) {
        return new Fraction(subtractor - subtrahend);
    }

    /**
     * Multiplication of fraction with fraction or integer or double
     *
     * @param a
     * @param b
     * @return
     */
    public static final Fraction multiplication(Fraction a, Fraction b) {
        return new Fraction(a.getNumerator() * b.getNumerator(), a.getDenominator() * b.getDenominator());
    }

    public static final Fraction multiplication(Fraction... fractions) {
        Fraction result = new Fraction(1);

        for (Fraction fr : fractions) {
            result = multiplication(result, fr);
        }

        return result;
    }

    public static final Fraction multiplication(Fraction a, int b) {
        return multiplication(a, new Fraction(b));
    }

    public static final Fraction multiplication(int a, Fraction b) {
        return multiplication(new Fraction(a), b);
    }

    public static final Fraction multiplication(Fraction a, double b) {
        return multiplication(a, new Fraction(b));
    }

    public static final Fraction multiplication(double a, Fraction b) {
        return multiplication(new Fraction(a), b);
    }

    public static final Fraction multiplication(double a, double b) {
        return new Fraction(a * b);
    }

    /**
     * Division of fraction with fraction or integer or double
     *
     * @param dividend
     * @param divisor
     * @return
     */
    public static final Fraction division(Fraction dividend, Fraction divisor) {
        return new Fraction(dividend.getNumerator() * divisor.getDenominator(), dividend.getDenominator() * divisor.getNumerator());
    }

    public static final Fraction division(Fraction... fractions) {
        Fraction result = fractions[0];

        for (int i = 1; i < fractions.length; i++) {
            result = division(result, fractions[i]);
        }

        return result;
    }

    public static final Fraction division(Fraction dividend, int divisor) {
        return division(dividend, new Fraction(divisor));
    }

    public static final Fraction division(int dividend, Fraction divisor) {
        return division(new Fraction(dividend), divisor);
    }

    public static final Fraction division(Fraction dividend, double divisor) {
        return division(dividend, new Fraction(divisor));
    }

    public static final Fraction division(double dividend, Fraction divisor) {
        return division(new Fraction(dividend), divisor);
    }

    public static final Fraction division(double dividend, double divisor) {
        return new Fraction(dividend / divisor);
    }

}
